﻿using Microsoft.AspNetCore.SignalR.Client;

namespace Digitalmes.Infrastructure.Hubs;

/// <summary>
/// SignalR Hub 构建器。
/// </summary>
public sealed class HubBuilder : IAsyncDisposable
{
    private readonly HubConnection _connection;

    /// <summary>
    /// 初始化一个新的 <see cref="HubBuilder"/> 实例。
    /// </summary>
    /// <param name="url">连接服务地址。</param>
    public HubBuilder(string url)
    {
        _connection = new HubConnectionBuilder()
                .WithUrl(url)
                .Build();

        _connection.Closed += async (error) =>
        {
            await Task.Delay(new Random().Next(1, 5) * 1000);
            await _connection.StartAsync();
        };
    }

    public void Register<T>(string methodName, Action<T> handler)
    {
        _connection.On<T>(methodName, t =>
        {
            handler(t);
        });
    }

    public void Register<T>(string methodName, Func<T, Task> handler)
    {
        _connection.On<T>(methodName, t =>
        {
            handler(t);
        });
    }

    /// <summary>
    /// 开启连接。
    /// </summary>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task StartAsync(CancellationToken cancellationToken = default)
    {
        while (true)
        {
            try
            {
                await _connection.StartAsync(cancellationToken);
                break;
            }
            catch when (cancellationToken.IsCancellationRequested)
            {
                break;
            }
            catch
            {
                await Task.Delay(5000, cancellationToken);
            }
        }
    }

    /// <summary>
    /// 停止连接。
    /// </summary>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task StopAsync(CancellationToken cancellationToken = default)
    {
        await _connection.StopAsync(cancellationToken);
    }

    public async ValueTask DisposeAsync()
    {
        await _connection.DisposeAsync();
    }
}
